#ifndef __log_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__
#define __log_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__

//*********************************************************************************************************************
#ifndef DISABLE_LOG_MACRO
#    ifdef DISABLE_LOG

#        define process( ... )

#        define log_err( ... )
#        define log_war( ... )
#        define log_nte( ... )
#        define log_inf( ... )
#        define log_dug( ... )

#        define log_out( ... )

#    else

/*********************************************************************
 * @brief 日志打印：log_xxx( format, ... );
 * @param format: 格式化输出字符串
 * @param ...：其它填充格式化输出的参数
 * @details 示例： log_inf( "index: %d.", 1 );
 */
#define log_eme    hude::_logger_t< hude::log_level_t::emEMERG   >::log
#define log_ale    hude::_logger_t< hude::log_level_t::emALERT   >::log
#define log_cri    hude::_logger_t< hude::log_level_t::emCRIT    >::log
#define log_err    hude::_logger_t< hude::log_level_t::emERR     >::log
#define log_war    hude::_logger_t< hude::log_level_t::emWARNING >::log
#define log_nte    hude::_logger_t< hude::log_level_t::emNOTICE  >::log
#define log_inf    hude::_logger_t< hude::log_level_t::emINFO    >::log
#define log_dug    hude::_logger_t< hude::log_level_t::emDEBUG   >::log
#define log_tra    hude::_logger_t< hude::log_level_t::emTRACE   >::log

/*********************************************************************
 * @brief 带标签的日志打印：tlog_xxx( tag, format, ... );
 * @param tag: 日志标签字符串
 * @param format: 格式化输出字符串
 * @param ...：其它填充格式化输出的参数
 * @details 示例： tlog_inf( "main", "index: %d.", 1 );
 */
#        define tlog_eme    hude::_logger_t< hude::log_level_t::emEMERG   >::log_tag
#        define tlog_ale    hude::_logger_t< hude::log_level_t::emALERT   >::log_tag
#        define tlog_cri    hude::_logger_t< hude::log_level_t::emCRIT    >::log_tag
#        define tlog_err    hude::_logger_t< hude::log_level_t::emERR     >::log_tag
#        define tlog_war    hude::_logger_t< hude::log_level_t::emWARNING >::log_tag
#        define tlog_nte    hude::_logger_t< hude::log_level_t::emNOTICE  >::log_tag
#        define tlog_inf    hude::_logger_t< hude::log_level_t::emINFO    >::log_tag
#        define tlog_dug    hude::_logger_t< hude::log_level_t::emDEBUG   >::log_tag
#        define tlog_tra    hude::_logger_t< hude::log_level_t::emTRACE   >::log_tag

/*********************************************************************
 * @brief 带标签的条件日志打印，如果输出等级低于当前日志等级则忽略输出：llog_xxx( tag, format, ... );
 * @param tag: 日志标签字符串
 * @param format: 格式化输出字符串
 * @param ...：其它填充格式化输出的参数
 * @details 示例： llog_inf( "main", "index: %d.", 1 );
 */
#        define llog_eme    hude::_logger_t< hude::log_level_t::emEMERG   >::log_tag_level
#        define llog_ale    hude::_logger_t< hude::log_level_t::emALERT   >::log_tag_level
#        define llog_cri    hude::_logger_t< hude::log_level_t::emCRIT    >::log_tag_level
#        define llog_err    hude::_logger_t< hude::log_level_t::emERR     >::log_tag_level
#        define llog_war    hude::_logger_t< hude::log_level_t::emWARNING >::log_tag_level
#        define llog_nte    hude::_logger_t< hude::log_level_t::emNOTICE  >::log_tag_level
#        define llog_inf    hude::_logger_t< hude::log_level_t::emINFO    >::log_tag_level
#        define llog_dug    hude::_logger_t< hude::log_level_t::emDEBUG   >::log_tag_level
#        define llog_tra    hude::_logger_t< hude::log_level_t::emTRACE   >::log_tag_level

/*********************************************************************
 * @brief info等级日志输出的简化调用接口: log( tag, format, ... );
 * @param tag: 日志标签字符串
 * @param format: 格式化输出字符串
 * @param ...：其它填充格式化输出的参数
 * @details 示例： log( "main", "index: %d.", 1 );
 */
#        define _log        hude::_logger_t< hude::log_level_t::emINFO    >::log

/*********************************************************************
 * @brief info等级日志输出带标签的简化调用接口: tlog( tag, format, ... );
 * @param tag: 日志标签字符串
 * @param format: 格式化输出字符串
 * @param ...：其它填充格式化输出的参数
 * @details 示例： tlog( "main", "index: %d.", 1 );
 */
#        define tlog        hude::_logger_t< hude::log_level_t::emINFO    >::log_tag

/*********************************************************************
 * @brief info等级的条件日志输出的简化调用接口: llog( tag, format, ... );
 * @param tag: 日志标签字符串
 * @param format: 格式化输出字符串
 * @param ...：其它填充格式化输出的参数
 * @details 示例： llog( "main", "index: %d.", 1 );
 */
#        define llog        hude::_logger_t< hude::log_level_t::emINFO    >::log_tag_level

#    endif //DISABLE_LOG
#endif //DISABLE_LOG_MACRO

//*********************************************************************************************************************
#ifndef DISABLE_LOG

#        include <cstdarg>
#        include <cstdio>
#        include <chrono>
#        include <cstring>
#        include <atomic>
#        include <hude/base/base_type.hpp>

namespace hude
{
    //-------------------------------------------------------------------------------------
    enum log_level_t
    {
        emMIN = -1,
        emMIN_LOG_LEVEL,

        emEMERG = emMIN_LOG_LEVEL,
        emALERT,
        emCRIT,
        emERR,
        emWARNING,
        emNOTICE,
        emINFO,
        emDEBUG,
        emTRACE,

        emMAX_LOG_LEVEL = emTRACE,
        emMAX,

        emCOUNT = emMAX - emMIN_LOG_LEVEL,
        emDEFAULT = emINFO
    };

    //-------------------------------------------------------------------------------------
    class log_debug_info_t
    {
    public:
        using texts_t = const char* (&)[log_level_t::emCOUNT];

    public:
        inline static log_level_t level() { return _level(); }
        inline static void level( log_level_t v ) { log_level_t& f = _level(); f = v; }

        inline static bool enable() { return _enable( log_level_t::emDEFAULT, level() ); }
        inline static bool enable( log_level_t v ) { return _enable( v, level() ); }

        inline static texts_t texts() {
            static const char* ts[log_level_t::emCOUNT] = { "ERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG", "TRACE", }; return ts; }

    private:
        inline static bool _enable( log_level_t t, log_level_t c ) { return static_cast< int >( t ) <= static_cast< int >( c ); }
        inline static log_level_t& _level() { static log_level_t f = log_level_t::emDEFAULT; return f; }

    };

    //-------------------------------------------------------------------------------------
    struct logger_t
    {
        std::atomic_flag lock_;

        static std::time_t now()
        {
            namespace chr = std::chrono;

            auto n = chr::time_point_cast< chr::milliseconds >( chr::system_clock::now() );

            return n.time_since_epoch().count();
        }

        static inline logger_t& get_default_logger()
        {
            static logger_t logger;

            return logger;
        }

        inline void log( int level, const char * format, ... ) noexcept
        {
            va_list argv;

            va_start( argv, format );

            vlog( level, "", 0, format, argv );

            va_end( argv );
        }

        inline void vlog( int level, const char* tag, uint_t tags, const char * format, va_list& argv ) noexcept
        {
            static const char tlevel[log_level_t::emCOUNT][8] = {
                "EME", "ALE", "CRI", "ERR", "WAR", "NOT", "INF", "DEG", "TRA"
            };

            int siz;

            {
                va_list as;
                va_copy( as, argv );
                siz = cio::vsnprintf( nullptr, 0, format, as );
                va_end( as );
            }

            const size_t count = 64U + tags + siz;

            char* buf = new char[ count ];

            auto t = static_cast< double >( (uint64_t)( now() ) ) / 1000.0f;

            siz = snprintf( buf, 64U + tags, "[%010.3f][%s] ", t, tlevel[level] );

            if( tags )
            {
                std::strncpy( buf + siz, tag, tags );
                siz += tags;
                buf[siz] = ' ';
                siz += 1;
            }

            {
                va_list as;
                va_copy( as, argv );
                siz += cio::vsnprintf( buf + siz, count - siz, format, as );
                va_end( as );
            }

            buf[siz + 0] = '\r';
            buf[siz + 1] = '\n';
            buf[siz + 2] = '\0';

            _log_out( level, buf, siz + 2 );

            delete[] buf;
        }

        void _log_out( int, const char*, size_t );
    };
    
    //-------------------------------------------------------------------------------------
    template< log_level_t _level > struct _logger_t
    {
        inline static void log_tag_level( const char* tag, const char * format, ... ) noexcept
        {
            if( ! log_debug_info_t::enable( _level ) ) return;

            va_list argv;

            va_start( argv, format );

            logger_t::get_default_logger().vlog( _level, tag, strlen( tag ),  format, argv );

            va_end( argv );
        }

        inline static void log_tag( const char* tag, const char * format, ... ) noexcept
        {
            va_list argv;

            va_start( argv, format );

            logger_t::get_default_logger().vlog( _level, tag, strlen( tag ),  format, argv );

            va_end( argv );
        }

        inline static void log( const char * format, ... ) noexcept
        {
            va_list argv;

            va_start( argv, format );

            logger_t::get_default_logger().vlog( _level, "", 0, format, argv );

            va_end( argv );
        }
    };

    /*********************************************************************
    * @brief 打印进度条
    * @param precent: 进度，范围：（0.0f ～ 100.0f），类型double
    * @details 示例：
    *      // precent: 初始进度，范围：（0.0f ～ 100.0f），类型double
    *      // zoom: 进度条的显示比例：建议在0.4～1.6之间
    *      // 符号：已达进度和未达进度的符号，这里是'#'和'_'
    *      hude::pbar_t pbar( 0.0f, zoom, '#', '_' );
    * 
    *      // precent: 进度，范围：（0.0f ～ 100.0f），类型double
    *      // title: 进度标题说明
    *      pbar( 10.0f, "显示10%的进度条" );
    */
    struct procbar_t
    {
        enum : size_t { emMAX = 250U };

        const double zoom_;
        const size_t size_;
        const char p_;
        const char z_;

        char bar_[emMAX + 1];

        procbar_t( double precent = 0, double zoom = 1.0F, char cp = '*', char cz = '.' ) noexcept :
             zoom_( _scope( zoom ) ), size_( static_cast< size_t >( 100 * zoom_ ) ), p_( cp ), z_( cz )
        {
            this->print_processbar( precent, "" );
        }

        ~procbar_t()
        {
            ::putc( '\n', stdout );
        }

        void process( double precent, const char* title = nullptr ) noexcept
        {
            this->print_processbar( precent, title );
        }

        void operator()( double precent, const char* title = nullptr ) noexcept
        {
            this->print_processbar( precent, title );
        }

        void print_processbar( double precent, const char* title = nullptr ) noexcept
        {
            if( precent < 0.0f || precent > 100.0f || zoom_ < 0.1 || zoom_ > ( 250.0f / 100.0f ) ) return;

            size_t p = static_cast< size_t >( precent * zoom_ );

            memset( bar_, p_, p );
            memset( bar_ + p, z_, size_ - p );
            bar_[size_] = '\0';

            auto& lock_ = logger_t::get_default_logger().lock_;

            while( lock_.test_and_set() );

            cio::printf( "%s | \033[0;31m%3.1f%%\033[0m | %s\r", bar_, precent, title? title : "" );

            fflush( stdout );

            lock_.clear();
        }

        static double _scope( double zoom )
        {
            return ( zoom < 0.1f )? 0.1f : ( (zoom > 2.5f)? 2.5f : zoom );
        }

        static procbar_t& one()
        {
            static procbar_t pbar;
            return pbar;
        }
    };

} //namespace hude

#    ifdef USING_PRIVATELIB_LOG

#        include <PrivateLib/module/logger/logger.hpp>
#        include <PrivateLib/module/logger/logger_console.hpp>

namespace hude
{
    struct logger_default_t
    {
        logger_default_t()
        {
            lib_module::logger::logger_console_stdout::install();
        }
    };
    
    inline void logger_t::_log_out( int level, const char* buf, size_t siz )
    {
        while( lock_.test_and_set() );

        lib_module::logger::logger::instance().sprint( level, buf, siz );

        lock_.clear();
    }
} //namespace hude

#    else

#        if defined( HUDE_SYSLOG )

#            include <cstdarg>
#            include <syslog.h>

namespace hude
{
    struct logger_default_t {};
    
    inline void logger_t::_log_out( int level, const char* buf, size_t siz )
    {
        while( lock_.test_and_set() );

        syslog ( level, "%s\r\n", buf );

        lock_.clear();
    }

    struct log_init_t
    {
        log_init_t( const char* tag, int opt = 0, int fly = LOG_USER ) { ::openlog( tag, opt, fly ); }
        ~log_init_t() { ::closelog(); }
    };
} //namespace hude

#        else

#            include <cstdarg>
#            include <cstdio>

namespace hude
{
    struct logger_default_t {};
    
    inline void logger_t::_log_out( int level, const char* buf, size_t )
    {
        static const char* colors[log_level_t::emCOUNT] =
        {
            "\033[41;33m",  "\033[41;37m", "\033[41;30m", 
            "\033[0;31m",   "\033[0;33m",  "\033[0;32m", 
            "\033[0;34m",   "\033[0;37m",  "\033[0m", 
        };

        static FILE* const fouts[log_level_t::emCOUNT] =
        {
            stderr, stderr, stderr,
            stderr, stdout, stdout,
            stdout, stdout, stdout
        };

        while( lock_.test_and_set() );

        cio::fprintf ( fouts[level], "%s%s\033[0m", colors[level], buf );

        lock_.clear();
    }
} //namespace hude

#        endif //defined( HUDE_SYSLOG )

#    endif //USING_PRIVATELIB_LOG

#else //DISABLE_LOG
namespace hude
{
    struct logger_default_t {};
}
#endif //DISABLE_LOG

#endif //__log_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__

